﻿/*This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>
	*/

using System.Text;
using System.IO;

namespace ZipLib
{
    /// <summary>
    /// Central directory at the end of zip file 
    /// </summary>
    public class ZipEndOfCentralDirectory
    {
        /// <summary>
        /// Initialize ZipEndOfCentralDirectory from stream
        /// </summary>
        /// <param name="s">Stream containing ZipEndOfCentralDirectory</param>
        public ZipEndOfCentralDirectory(Stream s) : this(new BinaryReader(s))
        {
        }
        /// <summary>
        /// The number of this disk (containing the end of central directory record)
        /// </summary>
        public short DiskNumber { get; set; }
        /// <summary>
        /// Number of the disk on which the central directory starts
        /// </summary>
        public short DiskCd { get; set; }
        /// <summary>
        /// The number of central directory entries on this disk
        /// </summary>
        public short DiskEntries { get; set; }
        /// <summary>
        /// Total number of entries in the central directory.   
        /// </summary>
        public short TotalEntries { get; set; }
        /// <summary>
        /// Size of the central directory in bytes
        /// </summary>
        public int CentralDirectorySize { get; internal set; }
        protected internal uint CentralDirectoryOffset { get; set; }
        /// <summary>
        /// An optional comment for the file.
        /// </summary>
        public string Comment
        {
            get { return _comment; }
            set
            {
                _comment = value;
                CommentLen = (short) value.Length;
            }
        }

        internal short CommentLen { get; private set; }

        private string _comment;

        /// <summary>
        /// Initialize ZipEndOfCentralDirectory from binary reader
        /// </summary>
        /// <param name="r">BinaryReader containing Zip stream</param>
        public ZipEndOfCentralDirectory(BinaryReader r)
        {
            if (r.ReadInt32() != 0x06054B50) throw new InvalidDataException();
            DiskNumber = r.ReadInt16();
            DiskCd = r.ReadInt16();
            DiskEntries = r.ReadInt16();
            TotalEntries = r.ReadInt16();
            CentralDirectorySize = r.ReadInt32();
            CentralDirectoryOffset = r.ReadUInt32();
            CommentLen = r.ReadInt16();
            Comment = Encoding.ASCII.GetString(r.ReadBytes(CommentLen));
        }

        /// <summary>
        /// Initialize a empty ZipEndOfCentralDirectory
        /// </summary>
        public ZipEndOfCentralDirectory() : this("")
        {
        }
        /// <summary>
        /// Initialize an empty ZipEndOfCentralDirectory with comment
        /// </summary>
        /// <param name="comment">Zip file comment</param>
        public ZipEndOfCentralDirectory(string comment)
        {
            DiskNumber = 0;
            DiskCd = 0;
            DiskEntries = 0;
            TotalEntries = 0;
            Comment = comment;
        }

        internal void Parse(BinaryWriter w)
        {
            w.Write(0x06054B50);
            w.Write(DiskNumber);
            w.Write(DiskCd);
            w.Write(DiskEntries);
            w.Write(TotalEntries);
            w.Write(CentralDirectorySize);
            w.Write(CentralDirectoryOffset);
            w.Write(CommentLen);
            w.Write(Encoding.ASCII.GetBytes(Comment));
        }
    }
}